#!/usr/bin/perl

## Parallel Elliptic Curve Cryptography Engine - An OpenSSL Engine which
## uses the SPU Elliptic Curve Library to provide optimized functionality
## on the CBEA.
##
## Copyright (C) 2008  Michael Annichiarico (mike.gcdeveloper@gmail.com)
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##


#print "pwd = '".`pwd`."'\n"; die;
sub Usage {
	print "$0 [DEBUG] <src directory> <engine directory> [build directory=srcdir/../build]\n";
}

my ($enginedir,$srcdir,$builddir,$builddebug);

if($ARGV[0] eq 'DEBUG') {
	shift @ARGV;
	$builddebug=1;	
}

($srcdirs = shift @ARGV) || die Usage();
($enginedir = shift @ARGV) || die Usage();

#$srcdir='"'.$srcdir.'"';
#$enginedir='"'.$enginedir.'"';
$srcdirs=~s/(\s)/\\$1/g;
$enginedir=~s/(\s)/\\$1/g;
$builddir=~s/(\s)/\\$1/g;

my ($CCADDDEBUGGING,$LDADDDEBUGGING) = ('','');
if($builddebug==1) {
	($CCADDDEBUGGING,$LDADDDEBUGGING) = ('-g','-g');
}


my @srcfiles = ();
my @files = ();
my $srcdir = '';
my $INCLUDEDIRS = '';

foreach $srcdir1 (split(/:/,$srcdirs)) {
print STDERR "srcdir1 = $srcdir1\n";
my @files1 = <${srcdir1}/e_pecc*>;
push(@files,@files1);
$srcdir = $srcdir1 if($srcdir eq '');
$INCLUDEDIRS.=' -I'.$srcdir1
}

($builddir = shift @ARGV) || ($builddir="$srcdir/../build");

system("rm -f $enginedir/e_pecc* $enginedir/tmp_pecc* $enginedir/dyn_pecc*");

print "Source files found:\n";
for(@files) {
	next if(!/\.(c|h|ec)$/);
	next if(/_err\.[hc]$/);
	print $_."\n";	
	push(@srcfiles,$_);
}

for(@srcfiles) {
my $filename = $1;
if(/^.*\/([^\/]*)$/) {
$filename = $1;
}
if(0!=system("rm -f \"$enginedir/$filename\"")) { die "rm -f \"$filename\" from engine directory ($enginedir) failed!\n"; }
if(0!=system("cp -sf \"$_\" \"$enginedir/\"")) { die "Copy to engine directory ($enginedir) failed!\n"; }
}

my $oldcccmd = `touch "$enginedir/e_atalla.c" && make -C "$enginedir" | grep atalla`; chomp($oldcccmd);
my $newcccmd = $oldcccmd;
my $speedcccmd = $oldcccmd;
$speedcccmd=~s/ -c //g;
$speedcccmd=~s/ -o //g;
$speedcccmd=~s/e_atalla\..//g;

$speedcccmd.=" \$(APPFLAGS) -DOPENSSL_NO_DES -I.. -o $builddir/\$(APPNAME) $enginedir/../apps/apps.o ${builddir}/tmp_pecc.o ${builddir}/*.o  -L$enginedir/..  -lcrypto -ldl";

$newcccmd=~s/e_atalla/e_pecc/g;
$newcccmd=~s/ (-D.*?) / \${CCADDDEBUGGING} -qpic -DENGINE_DYNAMIC_SUPPORT $INCLUDEDIRS $1 /;
$newcccmd=~s/e_pecc\.o/${builddir}\/tmp_pecc.o/g;

#$newcccmd.=' ../libssl.a';

my $compiler;
if($newcccmd=~/^(.*?)\s/) {$compiler=$1;} else {die "Cant find compilier line in new co command:\n".$newcccmd."\n";}
#$newcccmd=~s/^(.*?)\s/\$(CC) /;
$newcccmd=~s/-Wall//g;

$newcccmd=~s/-O3//g;

#print "old compile command:\n".$oldcccmd."\n";
#print "new compile command:\n".$newcccmd."\n";

#$mksdafix = "echo _SDA_DATA_=0x000f97a8 > SDAFIX.ld";

my $newldcmd = "$compiler \${LDADDDEBUGGING} -Wl,\"-z defs\" -fpic -Wl,-E -L${builddir} \$(M64) -shared -o ${builddir}/dyn_pecc.so ${builddir}/tmp_pecc.o engine_libcrypto.a \$(foreach lib,\$(LIBS),${builddir}/\$(lib)) \$(LIBDEPS)";

#my $newldcmd = $mksdafix." && "."\$(CC) \${LDADDDEBUGGING} -Wl,-M -Wl,\"-z defs\" -Wl,-E -L${builddir} \$(M64) -Wl,-shared -o ${builddir}/dyn_pecc.so SDAFIX.ld ${builddir}/tmp_pecc.o engine_libcrypto.a ${builddir}/\$(LIBS) \$(LIBDEPS)";
#my $newldcmd = "\$(CC) \${LDADDDEBUGGING} -qmkshrobj -Wl,\"-z defs\" -Wl,-E -L${builddir} \$(M64) -Wl,-shared -o ${builddir}/dyn_pecc.so ${builddir}/tmp_pecc.o engine_libcrypto.a ${builddir}/\$(LIBS) \$(LIBDEPS)";

#my $newldcmd = "/opt/cell/toolchain/bin/ppu32-ld -L/opt/cell/toolchain/lib/gcc/ppu/4.1.1/32 \${LDADDDEBUGGING} -z defs -E -L${builddir} \$(M64) -shared -o ${builddir}/dyn_pecc.so ${builddir}/tmp_pecc.o engine_libcrypto.a ${builddir}/\$(LIBS) \$(LIBDEPS) --start-group -lm -lc -lspe2 -lrt -lpthread -lgcc_s --end-group";

#print "new linking command:\n".$newldcmd."\n";

my $mkerrcmd = "perl ../util/mkerr.pl -nostatic -conf e_pecc.ec  -write e_pecc.c";

my $enginelibcryptomake = <<ENGINELIBCRYPTOMAKE;
engine_libcrypto.a: ../libcrypto.a FORCE
	cp ../libcrypto.a ./engine_libcrypto.a
	\$(RANLIB) ./engine_libcrypto.a

.PHONY: FORCE

ENGINELIBCRYPTOMAKE


my $makefile = "$srcdir/Makefile";

print "writing tmp makefile ($makefile)\n";
open(MAKEFILE,">$makefile") || die "Cant open temporary makefile ($makefile)\n";

print MAKEFILE <<THEMAKEFILE;
export

vpath $srcdir/..
-include Makefile.env

ENGINEDIR=$enginedir
THISFILE=$makefile
CCADDDEBUGGING=$CCADDDEBUGGING
LDADDDEBUGGING=$LDADDDEBUGGING
ifeq (\$(ENGINETYPE),)
ENGINETYPE:=engine
endif
eng_all:=\$(ENGINEDIR)/../crypto/engine/eng_all.c

all:
	\$(MAKE) -C \${ENGINEDIR} -f \${THISFILE} \$(ENGINETYPE)

release: all

debug: all

speed_static:
	$mkerrcmd
	$newcccmd
	cp -p \$(eng_all) \$(eng_all).backup
	sed -i -e 's:OPENSSL_NO_STATIC_ENGINE:OPENSSL_NO_STATIC_ENGINE\\n\\tENGINE_load_pecc();\\n:' \$(eng_all)
	make -C \$(ENGINEDIR)/..  build_libs || (cp -p \$(eng_all).backup \$(eng_all) && rm \$(eng_all).backup && false)
	-cp -p \$(eng_all).backup \$(eng_all) && rm \$(eng_all).backup
	$speedcccmd

app_static:
	$mkerrcmd
	$newcccmd
	cp -p \$(eng_all) \$(eng_all).backup
	sed -i -e 's:OPENSSL_NO_STATIC_ENGINE:OPENSSL_NO_STATIC_ENGINE\\n\\tENGINE_load_pecc();\\n:' \$(eng_all)
	make -C \$(ENGINEDIR)/..  build_libs || (cp -p \$(eng_all).backup \$(eng_all) && rm \$(eng_all).backup && false)
	-cp -p \$(eng_all).backup \$(eng_all) && rm \$(eng_all).backup
	cp -p \$(ENGINEDIR)/../libcrypto.a ${builddir}/

engine_static: update_libcrypto
	cp -p \$(eng_all) \$(eng_all).backup
	sed -i -e 's:OPENSSL_NO_STATIC_ENGINE:OPENSSL_NO_STATIC_ENGINE\\n\\tENGINE_load_pecc();\\n:' \$(eng_all)
#	cp \$(ENGINEDIR)/../Makefile \$(ENGINEDIR)/../Makefile.pecctmp
	make -C \$(ENGINEDIR)/..  build_libs  build_apps || (cp -p \$(eng_all).backup \$(eng_all) && rm \$(eng_all).backup && cp -p \$(ENGINEDIR)/../libcrypto.a.backup \$(ENGINEDIR)/../libcrypto.a && rm -f \$(ENGINEDIR)/../libcrypto.a.backup && false)
	-cp -p \$(eng_all).backup \$(eng_all) && rm \$(eng_all).backup
	-cp \$(ENGINEDIR)/../apps/openssl ${builddir}/

update_libcrypto: e_pecc_static.o
	cp -p \$(ENGINEDIR)/../libcrypto.a \$(ENGINEDIR)/../libcrypto.a.backup
	\$(AR) r \$(ENGINEDIR)/../libcrypto.a \$(ENGINEDIR)/e_pecc_static.o
	mkdir -p /tmp/artmp/ || echo ok
	rm -rf /tmp/artmp/*
	cd /tmp/artmp && \$(AR) -x ${builddir}/\$(LIBS)
	\$(AR) vr \$(ENGINEDIR)/../libcrypto.a /tmp/artmp/*
	\$(RANLIB) \$(ENGINEDIR)/../libcrypto.a
	#rm -f \$(ENGINEDIR)/lib
	#touch \$(ENGINEDIR)/e_atalla.c
	#make -C \$(ENGINEDIR) -f \$(THISFILE).static

e_pecc_static.o:
	$mkerrcmd
	$newcccmd
	cp ${builddir}/tmp_pecc.o \$@
#	$compiler -fPIC -r \${LDADDDEBUGGING} -L${builddir} \$(M64) -o \$@ ${builddir}/tmp_pecc.o ${builddir}/\$(LIBS) \$(LIBDEPS)

engine: engine_libcrypto.a
	$mkerrcmd
	$newcccmd
	$newldcmd

$enginelibcryptomake

postdebug: debug
	rm -f \$(THISFILE)

postrelease: release
	rm -f \$(THISFILE)


THEMAKEFILE
close(MAKEFILE);

$makefile = $makefile.".static";
print "writing tmp makefile ($makefile)\n";
open(MAKEFILE,">$makefile") || die "Cant open temporary makefile ($makefile)\n";

print MAKEFILE <<THEMAKEFILESTATIC;
export

include Makefile

vpath e_pecc_static% ${builddir}
#LIBNAMES+=pecc
#LIBSRC+=e_pecc.c
LIBOBJ+=e_pecc_static.o
#HEADER+=e_pecc_err.c e_pecc_err.h

THEMAKEFILESTATIC
close(MAKEFILE);

